#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>

#include "basic_io.h"
#include "lexical.h"

// 代码空间
CODE code[PROGRAM_SIZE] = {0};
// 代码指针
int cp = 1;
int code_size = 0;

// 可用的内存（26个变量）
VARIANT memory[MEMORY_SIZE] = {0}; // 支持double类型和string类型

void load_program(STRING filename)
{
  FILE *fp = fopen(filename, "r");
  int bg, ed;

  if (fp == NULL)
  {
    fprintf(stderr, "文件 %s 无法打开！\n", filename);
    exit(EXIT_FAILURE);
  }

  while (fscanf(fp, "%d", &code[cp].ln) != EOF) // 获取代码标注行号
  { // 逐行扫描源码
    printf("before ===> %d\r\n", code[cp].ln);
    if (code[cp].ln <= code[cp - 1].ln)
    { // 如果下标小的行号比下标大的行号大，则直接报错。
      fprintf(stderr, "Line %d: 标号错误！\n", cp);
      exit(EXIT_FAILURE);
    }

    fgets(code[cp].line, sizeof(code[cp].line), fp); // 获取这一行字符串，写入到line中
    for (bg = 0; isspace(code[cp].line[bg]); bg++)
      ;                                       // 去掉这一行的所有空格
    ed = (int)strlen(code[cp].line + bg) - 1; // 计算除去空格以外的字符串长度，-1是因为bg在上一行循环多+1了
    char *code_str = code[cp].line;
    printf("=====> %s\r\n", code_str);
    while (ed >= 0 && isspace(code[cp].line[ed + bg]))
    { // 继续去掉字符串末尾的空格
      ed--;
    }
    if (ed >= 0)
    {                                                     // 这是最终字符串除去前后空格的实际长度
      memmove(code[cp].line, code[cp].line + bg, ed + 1); // 将字符串非空格处移动到字符串起始处
      code[cp].line[ed + 1] = 0;                          // 字符串最后一个加上终止符号
    }
    else
    {
      code[cp].line[0] = 0; // 字符串加上终止符号
    }

    cp++; // 源码行号+1
    if (cp >= PROGRAM_SIZE)
    { // 如果行号比程序宏定义的最大值还大，则直接报错
      fprintf(stderr, "程序%s太大，代码空间不足！\n", filename);
      exit(EXIT_FAILURE);
    }
  }

  code_size = cp; // 更新行号到全局变量
  cp = 1;         // 重置行号
}

void exec_assignment(const STRING line)
{ // 表达式
  const char *s = line;
  int n;

  if (!strnicmp(s, "LET ", 4))
  {
    s += 4;
  }
  while (*s && isspace(*s))
  {
    s++;
  }
  if (!isalpha(*s) || isalnum(*(s + 1)))
  {
    perror("变量名错误！\n");
    exit(EXIT_FAILURE);
  }
  else
  {
    n = toupper(*s) - 'A';
  }

  do
  {
    s++;
  } while (*s && isspace(*s));
  if (*s != '=')
  {
    fprintf(stderr, "赋值表达式 %s 语法错误！\n", line);
    exit(EXIT_FAILURE);
  }
  else
  {
    memory[n] = eval(s + 1);
  }
}

void exec_input(const STRING line)
{
  const char *s = line;
  int n;

  assert(s != NULL);
  s += 5; // input -> 5

  while (*s)
  {
    while (*s && isspace(*s))
    { // 去掉空格
      s++;
    }
    if (!isalpha(*s) || isalnum(*(s + 1)))
    { // 判断紧随其后的是否是变量
      perror("变量名错误！\n");
      exit(EXIT_FAILURE);
    }
    else
    {
      n = toupper(*s) - 'A';
    }

    if (!scanf("%lf", &memory[n].i))
    { // 如果不是小数，那就是字符串
      int i;

      memory[n].type = var_string; // 设置变量类型为字符串类型
      if ((memory[n].s[0] = getchar()) == '"')
      { // 如果字符串第一个字符是双引号开头
        for (i = 0; (memory[n].s[i] = getchar()) != '"'; i++)
          ; // 将双引号里面的字符保存到内存中
      }
      else
      {
        for (i = 1; !isspace(memory[n].s[i] = getchar()); i++)
          ; // 获取字符
      }
      memory[n].s[i] = 0; // 字符最后一个设置为终止符号
    }
    else
    {
      memory[n].type = var_double; // 浮点数赋值，思考这里为什么没有值赋值？ 因为值赋值在scanf已经完成
    }

    do
    {
      s++;
    } while (*s && isspace(*s)); // 过滤掉所有空格
    if (*s && *s != ',')
    { // 如果没有逗号，就是错的
      perror("INPUT 表达式语法错误！\n");
      exit(EXIT_FAILURE);
    }
    else if (*s)
    { // 继续遍历
      s++;
    }
  }
}

void exec_print(const STRING line)
{
  STRING l;
  char *s, *e;
  VARIANT v;
  int c = 0;

  strcpy(l, line); // 赋值字符串
  s = l;           // 指针指向开头

  assert(s != NULL); // 判断是否为空
  s += 5;            // 过滤掉指令自身长度

  for (;;)
  {
    for (e = s; *e && *e != ','; e++)
    {
      // 去除字符串
      if (*e == '"')
      {
        do
        {
          e++;
        } while (*e && *e != '"');
      }
    }
    if (*e)
    { // 如果有值，最后一个符号设置为终止符号
      *e = 0;
    }
    else
    { // 否则，设置为空字符串
      e = NULL;
    }

    if (c++)
      putchar('\t');
    v = eval(s); // 解析字符串
    if (v.type == var_double) // 小数
    {
      printf("%g", v.i);
    }
    else if (v.type == var_string) // 字符串
    {
      printf("%s", v.s);
    }

    if (e) // 如果字符不为空
    {
      s = e + 1; // 指向下一个字符
    }
    else
    {
      putchar('\n'); // 换行
      break;
    }
  }
}
